package org.lbspoc.springboot1.boot.service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;
import org.bson.Document;
import org.lbspoc.springboot1.boot.model.LbsInfo;
import org.lbspoc.springboot1.boot.model.LbsReq;
//import org.lbspoc.springboot1.boot.util.JsonUtil;
import org.springframework.stereotype.Service;

import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;

@Service(value="mongoDbService")
public class MongoDbService {
	private static Logger logger = Logger.getLogger(MongoDbService.class);
	private static final double EARTH_RADIUS = 6378137.0;

	public MongoDbService() {
		// TODO Auto-generated constructor stub
	}
	
	public LbsInfo findByUserId(long uid) {
		logger.info("try to find " + uid);
		MongoDatabase db = MongoUtil.getInstance().getDB();
		String collectName = MongoUtil.getInstance().getCollectionName();
		MongoCollection<Document> col = db.getCollection(collectName);
		Document doc = new Document("user_id", uid);
		Document result = col.find(doc).first();
		if(result == null)
			return null;
		
//		String json = result.toJson();
//		LbsInfo info = JsonUtil.getInstance().convert(json, LbsInfo.class);
		LbsInfo info = MongoUtil.getInstance().docToLbsInfo(result);
		return info;
	}
	
	public void insert(LbsInfo info) {
		logger.info("insert a lbs " + info);
		MongoDatabase db = MongoUtil.getInstance().getDB();
		String collectName = MongoUtil.getInstance().getCollectionName();
		MongoCollection<Document> col = db.getCollection(collectName);
		Document doc = new Document();
//		doc.parse(JsonUtil.getInstance().toJson(info));
		MongoUtil.getInstance().fillDocument(doc, info);
		col.insertOne(doc);
	}
	
	public void update(LbsInfo info) {
		logger.info("update info " + info);
//		logger.info("insert a lbs " + info);
		MongoDatabase db = MongoUtil.getInstance().getDB();
		String collectName = MongoUtil.getInstance().getCollectionName();
		MongoCollection<Document> col = db.getCollection(collectName);
		Document update = new Document();
		MongoUtil.getInstance().fillDocument(update, info);
		Document updateOp = new Document("$set", update);
		col.updateOne(Filters.eq("user_id", info.getUser_id()), 
				updateOp);
	}
	
	public void deleteById(long uid) {
		logger.info("delete by id=" + uid);
		MongoDatabase db = MongoUtil.getInstance().getDB();
		String collectName = MongoUtil.getInstance().getCollectionName();
		MongoCollection<Document> col = db.getCollection(collectName);
		col.deleteOne(new Document("user_id", uid));
	}
	
	public List<LbsInfo> search(LbsReq req) {
		MongoDatabase db = MongoUtil.getInstance().getDB();
		String collectName = MongoUtil.getInstance().getCollectionName();
		MongoCollection<Document> col = db.getCollection(collectName);
		Iterator<Document> it = col.find().iterator();
		List<LbsInfo> ret = new ArrayList<LbsInfo>();
		while(it.hasNext()) {
			Document doc = it.next();
			double distance = getDistance(doc.getDouble("longitude"),
					doc.getDouble("latitude"), req.getLongitude(),
					req.getLatitude());
			if(distance <= req.getDistance()) {
				ret.add(MongoUtil.getInstance().docToLbsInfo(doc));
			}
		}
		return ret;
	}
	
	private double getDistance(double longitude1, double latitude1, 
			double longitude2, double latitude2) {
		double Lat1 = rad(latitude1);
		double Lat2 = rad(latitude2);
		double a = Lat1 - Lat2;
		double b = rad(longitude1) - rad(longitude2);
		double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
		    + Math.cos(Lat1) * Math.cos(Lat2)
		    * Math.pow(Math.sin(b / 2), 2)));
		s = s * EARTH_RADIUS;
		s = Math.round(s * 10000) / 10000;
		return s;
	}
	
	private double rad(double d) {
		return d * Math.PI / 180.0;
	}

}
